package com.wnxy.sddfp.system.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wnxy.sddfp.api.bank.TradeLogApi;
import com.wnxy.sddfp.common.constant.user.UserConstant;
import com.wnxy.sddfp.common.exception.Assert;
import com.wnxy.sddfp.common.model.dto.bank.BankCardAddDTO;
import com.wnxy.sddfp.common.model.dto.bank.CardBindDto;
import com.wnxy.sddfp.common.model.dto.bank.SignatureDto;
import com.wnxy.sddfp.common.model.dto.user.LoginDto;
import com.wnxy.sddfp.common.model.dto.user.UserRegisterDto;
import com.wnxy.sddfp.common.model.vo.user.LoginVo;
import com.wnxy.sddfp.common.result.enums.impl.BusinessCode;
import com.wnxy.sddfp.common.utils.JwtTemplate;
import com.wnxy.sddfp.common.utils.TokenUtils;
import com.wnxy.sddfp.system.entity.User;
import com.wnxy.sddfp.system.entity.UserCard;
import com.wnxy.sddfp.system.entity.UserDetail;
import com.wnxy.sddfp.system.mapper.UserDetailMapper;
import com.wnxy.sddfp.system.mapper.UserMapper;
import com.wnxy.sddfp.system.service.IUserCardService;
import com.wnxy.sddfp.system.service.IUserDetailService;
import com.wnxy.sddfp.system.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author yellow docker
 * @since 2025-03-18
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserDetailMapper userDetailMapper;
    @Autowired
    private IUserDetailService userDetailService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private JwtTemplate jwtTemplate;

    @Autowired
    private IUserCardService userCardService;

    /**
     * 用户注册
     *
     * @param userRegistDto
     */
    @Transactional(
            rollbackFor = Exception.class,
            propagation = Propagation.REQUIRED
    )
    @Override
    public void register(UserRegisterDto userRegistDto) {

        User usernameUser = getOne(Wrappers.lambdaQuery(User.class).eq(User::getUserName, userRegistDto.getUserName()));
        User phoneUser = getOne(Wrappers.lambdaQuery(User.class).eq(User::getPhone, userRegistDto.getPhone()));

        Assert.error(usernameUser != null, BusinessCode.USER_EXISTED);
        Assert.error(phoneUser != null, BusinessCode.USER_EXISTED);


        //保存用户
        User user = new User();
        user.setPhone(userRegistDto.getPhone());
        user.setUserName(userRegistDto.getUserName());
        //使用hutool工具加密pwd
        //String pwd = BCrypt.hashpw(userRegistDto.getPwd());
        user.setPwd(userRegistDto.getPwd());
        user.setUserType(UserConstant.USER_TYPE_PERSONAL);
        user.setUserStatus(false);
        this.save(user);

        //保存用户详情
        UserDetail userDetail = new UserDetail();
        userDetail.setId(user.getId());
        userDetail.setUserName(user.getUserName());
        userDetail.setPhone(user.getPhone());
        userDetail.setBorrowMoney(new BigDecimal("0"));
        userDetail.setUserCode("UC_" + UUID.randomUUID().toString().substring(0, 12));
        userDetail.setCardBindStatus(false);

        userDetailService.save(userDetail);

    }


    /**
     * 用户登录
     *
     * @param loginDto
     * @return
     */
    @Override
    public LoginVo Login(LoginDto loginDto) {

        return loginDto.getIsPhoneLogin() ? loginByPhone(loginDto) : loginByAccount(loginDto);
    }

    /**
     * 账号密码登陆
     *
     * @param loginDto
     * @return
     */
    private LoginVo loginByAccount(LoginDto loginDto) {

        //查询用户
        User user = getOne(Wrappers.lambdaQuery(User.class).eq(User::getUserName, loginDto.getLoginName()));

        Assert.error(ObjectUtils.isEmpty(user), BusinessCode.USER_LOGIN_ERROR);

        //验证密码
        boolean checkPwd = user.getPwd().equals(loginDto.getLoginSecret());

        Assert.error(!checkPwd, BusinessCode.USER_LOGIN_ERROR);

        //03 返回结果
        LoginVo loginVo = getLoginVo(user);

        return loginVo;
    }

    /**
     * 手机号码登录
     *
     * @param loginDto
     * @return
     */
    private LoginVo loginByPhone(LoginDto loginDto) {

        //从redis中获取验证码
        String code = stringRedisTemplate.opsForValue().get(loginDto.getLoginName());

        Assert.error(StringUtils.isEmpty(code), BusinessCode.USER_VERIFY_CODE_EMPTY);

        //校验验证码
        Assert.error(!loginDto.getLoginSecret().equals(code), BusinessCode.USER_VERIFY_CODE_ERROR);

        User user = getOne(Wrappers.lambdaQuery(User.class).eq(User::getPhone, loginDto.getLoginName()));


        if (user == null) {

            user = new User();

            Long registerId = IdUtil.getSnowflakeNextId();
            user.setId(registerId);
            user.setPhone(loginDto.getLoginName());
            String username = RandomUtil.randomString(6);
            user.setUserName(username);
            user.setUserType("1");
            user.setUserStatus(true);
            userMapper.insert(user);

            UserDetail userDetail = new UserDetail();
            userDetail.setId(registerId);
            userDetail.setUserName(username);
            userDetail.setPhone(loginDto.getLoginName());
            userDetail.setCardBindStatus(false);
            userDetail.setUserCode("UC" + UUID.randomUUID().toString().substring(0, 10));
            userDetailMapper.insert(userDetail);
        }

        //03 返回结果
        LoginVo loginVo = getLoginVo(user);

        return loginVo;
    }

    private LoginVo getLoginVo(User user) {
        Map<String, Object> payload = new HashMap<>();
        payload.put("userId", user.getId());
        payload.put("phone", user.getPhone());
        // 生成token
        String token = jwtTemplate.createToken(payload);
        // 返回
        return LoginVo.builder()
                .id(user.getId())
                .userName(user.getUserName())
                .phone(user.getPhone())
                .token(token)
                .build();
    }

    @Autowired
    private TradeLogApi tradeLogApi;

    /**
     * 用户绑卡：
     * 1、从token中获取userId
     * 2、校验：根据用户id查询u_user_detail用户表，根据CARD_BIND_STATUS字段判断是否已经绑卡
     * 3、如果未绑卡，保存保卡信息到u_user_card表
     * 4、更新用户表：把请求参数中的用户真实姓名、身份证号码更新到u_user表中
     * 5、生成请求流水号，用来访问托管代理，并更新u_user_detail表中流水号字段REQ_CODE
     * 6、远程访问托管代理服务（暂不实现）
     */
    @Override
    public SignatureDto addBankAccount(CardBindDto cardBindDto) {

        //1、从token中获取userId
        String userId = TokenUtils.getUserIdByToken("userId");

        //2、校验：根据用户id查询u_user_detail用户表，根据CARD_BIND_STATUS字段判断是否已经绑卡
        LambdaQueryWrapper<UserDetail> queryWrapper = Wrappers.lambdaQuery(UserDetail.class).eq(UserDetail::getId, userId);
        UserDetail userDetail = userDetailService.getOne(queryWrapper);
        Assert.error(userDetail.isCardBindStatus(), BusinessCode.USER_CARD_ALREADY_BINDED);

        //3、如果未绑卡，保存保卡信息到u_user_card表
        UserCard userCard = new UserCard();
        userCard.setUserId(Long.valueOf(userId));
        userCard.setCardNo(cardBindDto.getCardNo());
        userCard.setPhone(userDetail.getPhone());
        userCard.setStatus(false);

        userCardService.save(userCard);

        //4、更新用户表：把请求参数中的用户真实姓名、身份证号码更新到u_user表中

        LambdaUpdateWrapper<User> userLambdaUpdateWrapper = Wrappers.lambdaUpdate(User.class).eq(User::getId, userId)
                .set(User::getRealName, cardBindDto.getRealName())
                .set(User::getIdentityCode, cardBindDto.getIdentityCode());
        update(userLambdaUpdateWrapper);

        //5、生成请求流水号，用来访问托管代理，并更新u_user_detail表中流水号字段REQ_CODE

        String reqCode = UUID.randomUUID().toString().replace("-","").substring(0, 10);
        LambdaUpdateWrapper<UserDetail> userDetailLambdaUpdateWrapper = Wrappers.lambdaUpdate(UserDetail.class).eq(UserDetail::getId, userId)
                .set(UserDetail::getReqCode, reqCode);
        userDetailService.update(userDetailLambdaUpdateWrapper);

        //6、远程访问托管代理服务
        // 绑卡添加对象
        BankCardAddDTO bankCardAddDTO = new BankCardAddDTO();
        bankCardAddDTO.setReqCode(reqCode);
        bankCardAddDTO.setUserId(Long.valueOf(userId));

        //远程调用返回数据
        SignatureDto signatureDto = tradeLogApi.proxyBindCardLog(bankCardAddDTO);

        return signatureDto;
    }

}


